Раритет из мира термопринтеров

Приветствую всех!

Думаю, все мы себе представляем, как работает термопринтер. Но неподвижная пластина и ряд нагревательных элементов не всегда были типичной конструкцией такого устройства.

Итак, в сегодняшней статье разберёмся, как устроен и работает термопринтер старого образца с подвижной головкой. Узнаем, как его подключить к микроконтроллеру и запустить. Традиционно будет много интересного.

Суть такова

Давным-давно я уже писал пост о подключении термопечатающей головки к микроконтроллеру. И там я обмолвился, что существовали и более старые экземпляры, где головка не была неподвижной и которые сильно отличаются по управлению. Конечно, с моей стороны было бы неправильно упустить из виду такой экземпляр, тем более, что у меня он есть.

Обзор оборудования

Так уж получилось, что мне в своё время достались остатки от мониторов пациента компании Criticare (модель мне неизвестна, но, судя по всему, это 506N3). Измерительное оборудование было утрачено, но осталась горсть плат, а также несколько термопринтеров.

Сама плата. Запустить её мне не удалось, при включении она просто выдаёт какую-то ошибку, попутно сообщая, что датчик пульсоксиметра не подключён. Тем не менее, распаивать её я не буду, когда-нибудь мы к ней ещё вернёмся.

Вообще, медицинское оборудование само по себе — отдельная тема, заслуживающая далеко не одной статьи. Многие из этих девайсов очень крутые, а некоторые технологические решения, что там можно встретить, сильно удивляют.

А вот и термопринтер. Это STP211J-192 от Seiko/Epson. Как ясно из названия, разрешение по горизонтали у него 192 точки. Отчётливо видны два шаговых двигателя, печатающая головка, направляющая, червячный вал.

С обратной стороны ничего интересного.

Слева привод головки. Также тут находится концевой выключатель крайнего её положения.

Справа привод протяжки бумаги.

Из других устройств, где применялись такие термопринтеры, можно вспомнить VeriFone PrintPak. И если в модели 350 стоит самый обычный, то в более старом 300 — именно тот, что у нас. Мною весьма активно ищется такой аппарат, но пока что найти его не вышло.

Что нужно, чтобы управлять таким принтером?

В отличие от ранее рассмотренных экземпляров, этот простой и дубовый как никогда.
Из оборудования у нас имеются два мотора, головка, а также датчик её положения. Всё, больше ничего нет. Сама по себе головка представляет сборку из восьми резисторов, которые и служат нагревателями, никакой управляющей логики в ней нет.

Таким образом, помимо драйвера двигателей, понадобятся также силовые ключи для управления головкой.

Моторы

Поскольку шаговые двигатели тут униполярные, для управления ими было решено использовать ULN2804A. Восьми выходов как раз хватит для двух шаговиков, использующихся в принтере.

В даташите на принтер отыскались и последовательности включения двигателя. Так что проблем возникнуть не должно.

Помня об этом, подключаем моторы к ULNке. Выводы 1-8 соединяются с портами контроллера.

ТПГ

В отличие от более совершенных моделей, где термопечатающая головка имела свой собственный драйвер и управлялась по последовательному интерфейсу, здесь применена обычная сборка из восьми нагревательных резисторов. Сама головка съёмная, в даташите даже описана процедура её замены.

Сопротивление этих резисторов отличается в зависимости от модели принтера и составляет от четырнадцати до восемнадцати ом.

Итак, схема для управления головкой получается примерно такая.

Контроллер

Для управления решил взять всем известную Arduino — просто из-за пятивольтовых уровней и встроенного USB-UART. У меня нет ответной части к такому шлейфу, поэтому я припаял МГТФ прямо к контактам. Они там очень крупные, можно спокойно подпаяться, не боясь поплавить шлейф.

Собираем всё вместе. Термопринтер просто идеально подошёл по размерам на макетку. На ней же разместились преобразователь питания, две ULNки и плата Arduino. Термоголовка питается от пяти вольт, но брать их от USB нельзя, во время печати ток может составлять больше двух ампер. Всё, можно начинать эксперименты.

Управление моторами

И для начала, конечно, разберёмся с приводами. Тут всё достаточно просто — шаг мотора головки сдвигает её на расстояние одного пикселя, шаг мотора протяжки бумаги прокручивает её на расстояние четверти пикселя. Функции для всего этого получились вот такие:

uint8_t currentPhase = 0; uint8_t paperCurrentPhase = 0;  void paperStep() {   switch (paperCurrentPhase) {     case 2:       digitalWrite(A0, LOW);       digitalWrite(A1, LOW);       digitalWrite(A2, HIGH);       digitalWrite(A3, HIGH);       break;     case 3:       digitalWrite(A0, LOW);       digitalWrite(A1, HIGH);       digitalWrite(A2, HIGH);       digitalWrite(A3, LOW);       break;     case 0:       digitalWrite(A0, HIGH);       digitalWrite(A1, HIGH);       digitalWrite(A2, LOW);       digitalWrite(A3, LOW);       break;     case 1:       digitalWrite(A0, HIGH);       digitalWrite(A1, LOW);       digitalWrite(A2, LOW);       digitalWrite(A3, HIGH);       break;   }   if (paperCurrentPhase == 3) paperCurrentPhase = 0;   else paperCurrentPhase++; }  void headStep(int8_t dir) {   if (dir == -1) {     switch (currentPhase) {       case 1:         digitalWrite(A4, LOW);         digitalWrite(A5, LOW);         digitalWrite(11, HIGH);         digitalWrite(12, HIGH);         break;       case 0:         digitalWrite(A4, LOW);         digitalWrite(A5, HIGH);         digitalWrite(11, HIGH);         digitalWrite(12, LOW);         break;       case 3:         digitalWrite(A4, HIGH);         digitalWrite(A5, HIGH);         digitalWrite(11, LOW);         digitalWrite(12, LOW);         break;       case 2:         digitalWrite(A4, HIGH);         digitalWrite(A5, LOW);         digitalWrite(11, LOW);         digitalWrite(12, HIGH);         break;     }   }   else if (dir == 1) {     switch (currentPhase) {       case 0:         digitalWrite(A4, LOW);         digitalWrite(A5, LOW);         digitalWrite(11, HIGH);         digitalWrite(12, HIGH);         break;       case 1:         digitalWrite(A4, LOW);         digitalWrite(A5, HIGH);         digitalWrite(11, HIGH);         digitalWrite(12, LOW);         break;       case 2:         digitalWrite(A4, HIGH);         digitalWrite(A5, HIGH);         digitalWrite(11, LOW);         digitalWrite(12, LOW);         break;       case 3:         digitalWrite(A4, HIGH);         digitalWrite(A5, LOW);         digitalWrite(11, LOW);         digitalWrite(12, HIGH);         break;     }   }   if (currentPhase == 3) currentPhase = 0;   else currentPhase++; }

В отличие от управления головкой, время выполнения тут не слишком критично, поэтому используются «медленные» digitalWrite. Для привода ТПГ также добавлена возможность задания направления.

Инициализация

Отдельно стоит упомянуть про действия после запуска. Сразу после подачи питания МК не знает, где сейчас находится головка. Поэтому необходимо выставить её в нулевое положение — гнать влево, пока она не упрётся в концевой выключатель. Дальше необходимо сделать ещё несколько добавочных шагов, так как датчик срабатывает несколько раньше, чем головка упирается в крайнее положение. Если же ноль уже стоит, выводим головку из него и проверяем, не разомкнулся ли концевик. Если даже после существенного числа шагов он всё равно замкнут, значит, на моторы не подаётся питание или просто нет контакта.
Делается это всё примерно так:

void headInit() {   if (!digitalRead(10)) headReturn();   else {     for (int i = 0; i < 50; i++) {       headStep(1);       delay(10);     }     if (digitalRead(10)) {       Serial.println("Head drive error");       while (1);;     }     else headReturn();   } }  void headReturn() {   while (!digitalRead(10)) {     headStep(-1);     delay(10);   }   for (int i = 0; i < 6; i++) {     headStep(-1);     delay(10);   } }

Вообще, в даташите было сказано о двух шагах после касания концевика. Но в моём случае механизм имел достаточно сильный люфт, так что для уверенного возврата каретки число шагов увеличил до шести. Только тогда она стала нормально вставать в крайнее положение.

Управление головкой

Теперь очередь нагревателей. Чтобы задать их состояние, используется следующая функция:

void headControl(uint8_t toHead) {   PORTD &= B00000011;   PORTB &= B11111100;   PORTD |= ((toHead << 2) & B11111100);   PORTB |= ((toHead >> 6) & B00000011); } 

Для удобства загрузки восьми бит сразу применена работа с портами через регистры.

Печать символов

Как известно, головка печатает строку символов за один проход, как в матричном принтере. То есть за раз прожигается вертикальная линия из восьми точек. А это значит, что тот самый шрифт из предыдущего поста про термопринтер подойдёт как нельзя лучше, не придётся разбираться с преобразованием строки символов в восемь горизонтальных линий. Поэтому для печати символа необходимо всего лишь разбить его на пять столбцов, а потом последовательно прожечь их, каждый раз сдвигая головку на один шаг.

Делается это примерно так:

void printChar(char input) {   uint8_t vertical8dots = 0x00;   for (int i = 0; i < 5; i++) {     vertical8dots = pgm_read_byte(&FontTable[input][i]);     headControl(vertical8dots);     delay(3);     headControl(0x00);     headStep(1);     delay(10);   }   headDriveOff(); }

Задержка перед отключением головки определяет яркость печати. Не стоит пытаться изменить её поднятием напряжения, иначе головка может сдохнуть.

Печать строки

Ну, где символы, там и строка. Делается это всё достаточно просто:

void printString(String toPrinter) {   int target = 0;   for (int i = 0; i < 20; i++) {     headStep(1);     delay(10);   }   if (toPrinter.length() > 18) target = 18;   else target = toPrinter.length();   for (int i = 0; i < target; i++) {     printChar(toPrinter[i]);     for (int n = 0; n < 3; n++) {       headStep(1);       delay(10);     }   }   headReturn();   headDriveOff(); }

Ничего сложного: прожигаем очередной символ, затем сдвигаем головку на некоторое число пикселей (в моём случае три) и так до конца строки. Затем возвращаем головку на место, и можно проматывать бумагу.

В итоге вся программа получилась такая:

#include "FontTable.h"  uint8_t currentPhase = 0; uint8_t paperCurrentPhase = 0;  void setup() {   for (int i = 2; i <= 9; i++) pinMode(i, OUTPUT);   pinMode(10, INPUT_PULLUP);   pinMode(11, OUTPUT);   pinMode(12, OUTPUT);   for (int i = 14; i <= 19; i++) pinMode(i, OUTPUT);   Serial.begin(115200);   headInit();   headDriveOff(); }  void paperStep() {   switch (paperCurrentPhase) {     case 2:       digitalWrite(A0, LOW);       digitalWrite(A1, LOW);       digitalWrite(A2, HIGH);       digitalWrite(A3, HIGH);       break;     case 3:       digitalWrite(A0, LOW);       digitalWrite(A1, HIGH);       digitalWrite(A2, HIGH);       digitalWrite(A3, LOW);       break;     case 0:       digitalWrite(A0, HIGH);       digitalWrite(A1, HIGH);       digitalWrite(A2, LOW);       digitalWrite(A3, LOW);       break;     case 1:       digitalWrite(A0, HIGH);       digitalWrite(A1, LOW);       digitalWrite(A2, LOW);       digitalWrite(A3, HIGH);       break;   }   if (paperCurrentPhase == 3) paperCurrentPhase = 0;   else paperCurrentPhase++; }  void headStep(int8_t dir) {   if (dir == -1) {     switch (currentPhase) {       case 1:         digitalWrite(A4, LOW);         digitalWrite(A5, LOW);         digitalWrite(11, HIGH);         digitalWrite(12, HIGH);         break;       case 0:         digitalWrite(A4, LOW);         digitalWrite(A5, HIGH);         digitalWrite(11, HIGH);         digitalWrite(12, LOW);         break;       case 3:         digitalWrite(A4, HIGH);         digitalWrite(A5, HIGH);         digitalWrite(11, LOW);         digitalWrite(12, LOW);         break;       case 2:         digitalWrite(A4, HIGH);         digitalWrite(A5, LOW);         digitalWrite(11, LOW);         digitalWrite(12, HIGH);         break;     }   }   else if (dir == 1) {     switch (currentPhase) {       case 0:         digitalWrite(A4, LOW);         digitalWrite(A5, LOW);         digitalWrite(11, HIGH);         digitalWrite(12, HIGH);         break;       case 1:         digitalWrite(A4, LOW);         digitalWrite(A5, HIGH);         digitalWrite(11, HIGH);         digitalWrite(12, LOW);         break;       case 2:         digitalWrite(A4, HIGH);         digitalWrite(A5, HIGH);         digitalWrite(11, LOW);         digitalWrite(12, LOW);         break;       case 3:         digitalWrite(A4, HIGH);         digitalWrite(A5, LOW);         digitalWrite(11, LOW);         digitalWrite(12, HIGH);         break;     }   }   if (currentPhase == 3) currentPhase = 0;   else currentPhase++; }  void lineFeed() {   for (int i = 0; i < 48; i++) {     paperStep();     delay(10);   }   paperDriveOff(); }  void headReturn() {   while (!digitalRead(10)) {     headStep(-1);     delay(10);   }   for (int i = 0; i < 6; i++) {     headStep(-1);     delay(10);   } }  void headInit() {   if (!digitalRead(10)) headReturn();   else {     for (int i = 0; i < 50; i++) {       headStep(1);       delay(10);     }     if (digitalRead(10)) {       Serial.println("Head drive error");       while (1);;     }     else headReturn();   } }  void headDriveOff() {   digitalWrite(A4, LOW);   digitalWrite(A5, LOW);   digitalWrite(11, LOW);   digitalWrite(12, LOW); }  void paperDriveOff() {   digitalWrite(A0, LOW);   digitalWrite(A1, LOW);   digitalWrite(A2, LOW);   digitalWrite(A3, LOW); }  void headControl(uint8_t toHead) {   PORTD &= B00000011;   PORTB &= B11111100;   PORTD |= ((toHead << 2) & B11111100);   PORTB |= ((toHead >> 6) & B00000011); }  void printChar(char input) {   uint8_t vertical8dots = 0x00;   for (int i = 0; i < 5; i++) {     vertical8dots = pgm_read_byte(&FontTable[input][i]);     headControl(vertical8dots);     delay(3);     headControl(0x00);     headStep(1);     delay(10);   }   headDriveOff(); }  void printString(String toPrinter) {   int target = 0;   for (int i = 0; i < 20; i++) {     headStep(1);     delay(10);   }   if (toPrinter.length() > 18) target = 18;   else target = toPrinter.length();   for (int i = 0; i < target; i++) {     printChar(toPrinter[i]);     for (int n = 0; n < 3; n++) {       headStep(1);       delay(10);     }   }   headReturn();   headDriveOff(); }  void loop() {   String inputString = Serial.readString();    if (inputString.length() > 0)   {     printString(inputString);     lineFeed();   } }

Пробуем что-то напечатать… и оно даже работает! К слову говоря, шрифт очень сильно напоминает тот, что выдаёт матричный принтер. Справа на фото как раз такая распечатка — сходство весьма сильное.

И я даже записал видео с этим:

Двунаправленная печать

А что, если реализовать печать как в матричном принтере — при каждом проходе каретки? Официально этот механизм такое не поддерживает, но ничего не мешает это попробовать.
Для того, чтобы такое реализовать, необходимо поменять алгоритм печати: будем прожигать строку не посимвольно, а всю разом. Для этого создадим массив, куда запишем все символы вместе с пробелами сразу, а потом будем его печатать. Получилось примерно следующее:

void printString(String toPrinter) {   uint8_t index = 0;   uint8_t toHead[192];   for (int i = 0; i < 192; i++) toHead[i] = 0x00;   int target = 0;   for (int i = 0; i < 20; i++) {     headStep(1);     delay(10);   }   if (toPrinter.length() > 18) target = 18;   else target = toPrinter.length();   for (int i = 0; i < target; i++) {     for (int n = 0; n < 5; n++) {       toHead[index] = pgm_read_byte(&FontTable[toPrinter[i]][n]);       index++;     }     index += 3;   }   for (int i = 0; i < 146; i++) {     headControl(toHead[i]);     delay(3);     headControl(0x00);     headStep(1);     delay(10);   }   headMoveDirection = -1;   headDriveOff(); }

Как оказалось, эффективная ширина печати намного меньше 192 пикселей, а без отступов по краям распечатка выглядит так себе. Тем не менее, размер массива в 192 байта я оставил, для совместимости с другими модификациями этого принтера (ну, или если кому-то захочется печатать без полей).

Запускаем и убеждаемся, что всё работает как надо. Как нетрудно догадаться, алгоритм печати в обратном направлении совершенно идентичен:

void printStringReversed(String toPrinter) {   uint8_t index = 0;   uint8_t toHead[192];   for (int i = 0; i < 192; i++) toHead[i] = 0x00;   int target = 0;   if (toPrinter.length() > 18) target = 18;   else target = toPrinter.length();   for (int i = 0; i < target; i++) {     for (int n = 0; n < 5; n++) {       toHead[index] = pgm_read_byte(&FontTable[toPrinter[i]][n]);       index++;     }     index += 3;   }     for (int i = 148; i >= 0; i--) {     headControl(toHead[i]);     delay(3);     headControl(0x00);     headStep(-1);     delay(10);   }   headReturn();   headDriveOff();   headMoveDirection = 1; }

Чтобы сделать печать максимально простой, добавил отдельную функцию, где бы выбиралось нужное направление:

void processPrinting(String input) {   if (headMoveDirection == 1) printString(input);   else if (headMoveDirection == -1) printStringReversed(input);   lineFeed(); }

Работает. Но тут я столкнулся уже с чисто конструктивными ограничениями: как бы я ни подкручивал общее число шагов, заставить строки быть точно на одном уровне не вышло. Люфт механизма всё же даёт о себе знать.

Получилось примерно так:

На видео заметен ещё один глюк: при печати в обратном направлении теряются первые два символа. Это косяк не алгоритма печати, а исключительно функции для вывода этой таблицы символов.

Вот как-то так

Понятное дело, что в наши дни этот принтер — скорее игрушка, чем действительно рабочий девайс. И для реальных проектов давно уже существуют более простые в управлении принтеры. Тем не менее, запустить такое было реально интересно. А некоторое сходство с матричным принтером ещё больше добавляет крутизны этому девайсу.

Такие дела.


Возможно, захочется почитать и это:


ссылка на оригинал статьи https://habr.com/ru/articles/752870/

Как конфигурировать функциональность мобильных приложений

При разработке мобильных приложений часто возникает необходимость иметь возможность включать/выключать или параметризировать функциональность по разным причинам как при изначальной сборке приложения, так и в уже собранном или даже выпущенном приложении. В этой статье мы рассмотрим разные подходы к конфигурированию функциональности мобильных приложений и их преимущества и недостатки.

Конфигурирование функциональности может быть полезно для разных целей, например:

  • Добавления отладочной панели или ключей для тестирования приложения

  • Управления новой функциональностью, которая еще не протестирована или не готова к релизу

  • Запуска AB-тестов для проверки продуктовых гипотез и измерения эффективности изменений

  • Адаптации приложения к разным регионам, языкам или платформам

  • Реагирования на изменения внешних условий, например рекламных кампаний или доступности сервисов

В зависимости от того, на каком этапе жизненного цикла приложения мы хотим конфигурировать его функциональность, мы можем использовать разные способы

Конфигурация на уровне сборки

Самый простой вариант конфигурации — это использование параметров, которые задаются при сборке приложения. Такие параметры могут, например, отвечать за добавление в код приложения кода отладочной панели, или для задания отладочных ключей. Тогда для сборки отладочной версии приложения может использоваться один конфигурационный файл, а для релизной — другой.

Пример конфигурационного файла (Android приложение):

// gradle.properties isDebugPanelEnabled=true
// build.gradle dependencies {     ...     if (getProperty("isDebugPanelEnabled")) {         implementation ':libs:debug'     }     ... } 

Главное преимущество такой конфигурации — это простота реализации, но, когда приложение уже собрано, изменить значения параметров уже не получится. Такая конфигурация не позволяет управлять функциональностью для конкретных пользователей или групп пользователей.

Локальная конфигурация

Часто бывает необходимо иметь версию приложения, в которой можно включать/выключать и настраивать существующую функциональность на одной сборке. Например, такая необходимость часто возникает при тестировании приложения, когда в одной сборке есть как отлаженная функциональность, так и новая, непротестированная. Такую функциональность хочется “убрать под флаг”, чтобы в случае обнаружения в новой функциональности дефектов не блокировать релизный процесс мобильного приложения.

Для реализации такой возможности необходимо разработать отдельную отладочную панель — экран, на котором можно управлять состоянием флагов. Хороший пример — отладочная панель в ОС Android. Она позволяет, например, настраивать плотность пикселей на устройстве или включить отображение границ UI-компонентов.

Отладочная панель в ОС Android

Отладочная панель в ОС Android

Преимущество локальной конфигурации — это возможность изменять значения флагов в любой момент на конкретном устройстве. Недостаток — это необходимость разработки и поддержки отладочной панели, а также отсутствие возможности управлять функциональностью удаленно.

Удалённая конфигурация

В некоторых случаях необходимо управлять параметрами удаленно с сервера. В этом случае на старте приложение запрашивает конфигурацию у специального сервера и использует ее для включения/выключения функциональности и ее настройки. Такая необходимость может появиться если, например, необходимо выложить приложение с функциональностью в выключенном состоянии, а затем включить ее в определенный момент времени, например к началу рекламной кампании.

Дополнительная механика, которую можно поддержать для удаленных конфигураций — это раздача конфигураций “на процент”. В этом случае для части пользователей возвращаются одни значения, а остальным — другие. Это можно использовать, например, для постепенного включения новой функциональности и соответствующего увеличения нагрузки на новые методы API, чтобы убедиться, что сервер справится с нагрузкой.

Дополнительно для удаленных флагов можно предусмотреть версионирование, так как при обнаружении дефектов в приложении и их последующем исправлении при переключении флага функциональность с дефектом станет доступна пользователям, если они не обновили приложение.

Этот вариант очень удобен для запуска функциональности в привязке ко времени, а также для поэтапной раскатки функциональности на часть пользователей. Тем не менее здесь необходимо реализовывать клиент-серверное взаимодействие и административную панель для управления состояниями флагов. В самых простых случаях для реализации удаленной конфигурации можно использовать готовые решения, например, Firebase Remote Config.

Конфигурация AB-теста

Однако, самым распространенным для сложных продуктов сценарием, подразумевающим включение/выключение функциональности и управление ее параметрами, является запуск AB-экспериментов. С точки зрения приложения этот вариант очень похож на вариант с удаленной конфигурацией, но логика на серверной стороне отличается. В рамках AB-теста сегмент пользователей делится на группы: контрольную, которая получает исходную версию продукта, и тестовую, которая получает версию продукта с новой функциональностью. Каждая группа пользователей получает свою версию конфигурации и соответственно, по-разному сконфигурированную функциональность в приложении. По каждой группе пользователей измеряются продуктовые метрики, и если версия приложения с тестовой конфигурацией признается лучшей, то такой эксперимент принимают и версия приложения с новой функциональностью становится исходной версией для новых экспериментов. Вопросы выбора сегмента пользователей для AB-эксперимента и их дальнейшее разбиение на группы эксперимента вынесем за рамки этой статьи.

Реализация административного раздела для создания AB-экспериментов, настройка их параметров, а также настройка инструментов для анализа их результатов — отдельная и сложная задача. Тем не менее для самых простых случаев также можно использовать готовые решения, например, Firebase.

Всё вместе

Очень часто все эти способы управлять функциональностью приложения реализуют вместе, и возникает вопрос, а какой источник для значения параметра выбрать, если значения из разных источников отличаются.

Локальная конфигурация — это самый удобный способ изменить значение параметров на конкретном устройстве. Поэтому этот источник можно считать самым “сильным” и в первую очередь использовать значение оттуда. Если в локальной конфигурации значение параметра не переопределено, то необходимо использовать значение, полученное с сервера.

Удаленная конфигурация и конфигурация AB-теста объединяет то, что обе они запрашиваются с сервера и с точки зрения мобильного приложения часто неразличимы. Эти варианты редко используются вместе, но такие сценарии возможны. Например, когда новую функциональность необходимо запустить через AB-эксперимент, но при этом иметь возможность отключать ее совсем без остановки теста, если, например, используемый для работы функциональности сервис временно отказал. В таких случаях предпочтение следует отдавать значению удаленной конфигурации.

Параметры из конфигурации на уровне сборки очень часто используются в качестве значений по умолчанию, поэтому используются, если ни в одном другом источнике они не переопределены.

Выбор источника значения параметра

Выбор источника значения параметра

Выводы

В статье были рассмотрены подходы к конфигурированию функциональности мобильных приложений как на этапе сборки, так и когда приложение уже собрано или даже выпущено. Для реализации этих подходов есть готовые решения, однако в больших командах часто используются собственные решения, которые учитывают специфику конкретных команд и продуктов. При использовании таких конфигураций можно упростить процесс разработки и тестирования мобильного приложения, а также обеспечить возможность проверки продуктовых гипотез через AB-тесты.


ссылка на оригинал статьи https://habr.com/ru/articles/752892/

Измерение диэлектрической проницаемости — необходимость при создании устройств в мм-диапазоне (перевод)

От переводчика

Меня зовут Олеся (Leka_engineer), я инженер-разработчик СВЧ устройств на печатных платах (ПП). Поэтому мне так интересна тема производства печатных плат, подложек для ПП и измерения их эпсилон.

Я уже немного писала про свой опыт измерения диэлектрической проницаемости ламинатов вот тут. Также хочу в этом предисловии отметить работы других авторов:

  • Автор этой статьи изготовил и измерил три вида образцов; два типа резонаторов (кольцевой и в виде шлейфа) и образец для измерения фазовым методом

  • Первоисточник этого перевода — тоже авторства Джона Кунрода из Rogers Corp. В статье как раз описаны методы резонатора и фазовый (с формулами).

  • Автор этой статьи провёл эксперимент и определил эпсилон образцов линий с разной длиной (фазовый метод). Статья интересна тем, что также приводится сравнение результатов эксперимента с электродинамической моделью. И советую заглянуть в раздел списка литературы.

Автор оригинала данного перевода — Джон Кунрод, технический специалист Rogers Corp. В блоге на их сайте и в журнале Microwave Journal много статей про типы линий и про определение эпсилон материала. Также он —  автор множества видеороликов на канале Rogers Corp (например вот видео про обзор методов оценки эпсилон). Я часто рекомендую эти видео в своём телеграм канале. Для лучшего понимания перевода, считаю нужным проиллюстрировать его двумя скриншотами из этого видео.

1 График зависимости диэлектрической проницаемости материала от частоты (в общем случае)

1 График зависимости диэлектрической проницаемости материала от частоты (в общем случае)
2 График зависимости измеренной диэлектрической проницаемости ламината Rogers RO4003C толщиной 0,508 мм при использовании разных методов. Синяя линия - фазовый метод, Две точки FSR на двух частотах в левой части графика. И две точки, определённые с помощью резонаторного кольца.

2 График зависимости измеренной диэлектрической проницаемости ламината Rogers RO4003C толщиной 0,508 мм при использовании разных методов. Синяя линия — фазовый метод, Две точки FSR на двух частотах в левой части графика. И две точки, определённые с помощью резонаторного кольца.
примечание переводчика — FSR

Иллюстрация FSR («целого листа») метода. Скриншот из этого видео.

3 Метод FSR

3 Метод FSR

Измерение диэлектрической проницаемости —  необходимость при создании устройств в мм-диапазоне

Диэлектрическая проницаемость (Dk, ε) — важная отправная точка для многих разработчиков ПП, как для определения параметров ламината для последующего изготовления плат, так и при наличии неизвестного материала «на руках» и последующей симуляции дизайна на нём в компьютере. Особенно важно точно знать эпсилон при разработке устройств на более высоких частотах, где длина волны становится меньше, и размеры элементов топологии критически важны. При изготовлении прототипов в мм-диапазоне точность первоначального определения Dk подложки во многом определяет успех. Эпсилон материала определяется измерениями и последующими вычислениями на основе известных параметров материала, тестовой топологии и применённых оснасток.

Не существует идеального метода оценки диэлектрической проницаемости. Именно поэтому, существует множество способов измерения эпсилон. Методы имеют разные уровни сложности и точности и могут показать разные результаты при измерении одного и того же материала. Электрически цепи в мм-диапазоне очень чувствительны, поэтому отклонения Dk подложки приводят к задержкам в процессе разработки. Если эпсилон материала не как в даташите, прототипы цепей на этом материале, должны быть изготовлены в соответствии с максимально точным значением Dk, особенно, если это схема в мм-диапазоне. Разные методы оценки диэлектрической проницаемости могут давать разный результат, поэтому базовое представление о том, как работают разные методики измерения эпсилон, будут полезны при проектировании цепей в миллиметровом диапазоне.

В то время как цепи и их применение «забирается» всё выше по частотному диапазону, разрабатываются новые методы оценки параметров материалов подложек Dk и Df (коэффициент рассеяния). Измерительные техники, определяющие Dk можно разделить на основанные на материале и на цепи (топологии). Первые подразумевают помещение образца в тестовую оснастку, вторые —  изготовление печатной платы с топологией, после измерения параметров которой вычисляется Dk. Большинство «материальных» методов используют голый диэлектрик, без слоя меди, методы с печатными платами, естественно, подразумевают наличие проводника.

«Материальные» методы обычно определяют эпсилон в определённой частотной точке (и при условии определённой температуры), а основанные на топологии методы могут быть применены для определения эпсилон на разных частотах в зависимости от типа тестовой цепи. Цепи на основе линий передачи, например микрополосковой или симметричной, могут быть измерены со свипированием по частоте. Цепи на основе резонаторов —  на одной частоте (на которой наблюдается резонанс).

Многие методы оценки эпсилон стандартизированы в системе IPC. Например, IPC TM-650 представляет собой целую коллекцию методик характеризации Dk, Df и других важных параметров. Но, несмотря на стандратизацию и чёткое описание методик измерений, разные методики будут «давать» различные значения Dk для одного и того же материала. Знание того, как отличаются разные методы, может помочь разработчикам лучше разбираться в применении материалов, особенно, если их параметры измерены по разным методикам.

Из-за того, что при использовании разных методик, получаются разные значения эпсилон, крупные производители, например такие как Rogers Corporation, указывают в даташитах несколько значений Dk: «process» и «design». В Rogers, первая цифра получена по методике, описанной в стандарте IPC-TM-650 2.5-5.5 , на одной частотной и температурной точке. А «design» значение применимо к довольно широкому частотному диапазону, причём это значение может быть получено комбинацией множество тестов, как основанных на материале, так и на топологии. Для большинства разработчиков именно вторая цифра —  нужная, она показывает практическое значение Dk материала в указанном диапазоне частот. Если рабочая частота выше указанного диапазона, например разработка ведётся в мм-диапазоне частот (30-300 ГГц), разработчик может сам провести эксперимент и охарактеризовать материал в нужном себе диапазоне частот. И понимание различия методов и различия результатов этих методов поможет разработчику лучше подготовиться к проведению измерений. Этот перевод сделан Leka_engineer

например:
4 скриншот из даташита на 4000-ю серию Rogers

4 скриншот из даташита на 4000-ю серию Rogers

Сравнение методов оценки Dk

Точность каждого метода зависит от множества факторов, таких как точность калибровки измерительного оборудования (чаще всего ВАЦ), различия в тестовых оснастках и отклонения ширины дорожек и зазоров при изготовлении печатных плат с линиями передачи или резонаторами. Большинство материалов подложек анизотропны, и эпсилон различно в разных направлениях: x (длина), y (ширина) и z (толщина). В то время как методики, определяющие Dk по осям x и y — просто полезны, измерения, позволяющие вычислить Dk по оси z представляют наибольший интерес потому, что поле линии находится как раз между землёй и сигнальным проводником.

Методика симметричной линии, представляющей собой проводник, зажатый между двумя пластинами диэлектрика, описана в стандарте IPC-TM-650 2.5-5.5, и используется в корпорации Rogers для определения диэлектрической проницаемости материалов, также таким образом можно определить Df (оба параметра по оси z). Этот метод довольно точный и имеет хорошую повторяемость, но «даёт» значение эпсилон только на одной точке —  10 ГГц. Методика характеризует голый материал, без проводника. В процессе тестирования материал помещают в специальную оснастку с платой с резонатором (на симметричной линии). Металлические пластины оснастки, которые зажимают образец и резонатор, являются экранами симметричной линии. В целях получения результатов с хорошей повторяемостью, оснастка должна быть собрана без воздушных зазоров, так как воздух с эпсилон 1 понизит эффективную (измеренную) эпсилон конструкции и эпсилон исследуемого материала будет определена неверно.

примечание переводчика и иллюстрация

На рисунке 1 упомянутой выше публикации показан этот метод (только перевод рисунка сделан не совсем корректно на мой взгляд — резонатор не микрополосковый, а на симметричной линии; испытательной установкой принято обычно называть некий стенд, в оригинале это fixture — оснастка).

5 рисунок из публикации-перевода "Определение параметров материалов печатных плат в миллиметровом диапазоне" (что тоже неточно, оригинал можно перевести как "Характеризация материалов для цепей в мм-диапазоне волн" или вставить "для" перед "печатных плат")

5 рисунок из публикации-перевода «Определение параметров материалов печатных плат в миллиметровом диапазоне» (что тоже неточно, оригинал можно перевести как «Характеризация материалов для цепей в мм-диапазоне волн» или вставить «для» перед «печатных плат»)

Оснастки —  почти самое главное при измерениях параметров материалов в методах, основанных на материале. Для измерений обычно используют некий резонатор, и, зная толщину образцов, можно определить его параметры. Повторяемость и точность «материальных» методов зависит от качества изготовления тестовой оснастки, в то время как повторяемость и точность основанных на топологии методов зависит от качества (точности) изготовления топологии на плате.

В методах, позволяющих определить эпсилон материала, используется несколько типов резонансных структур, включая (далее дословный перевод) метод «разделённого объёмного резонатора» (SPDR), метод «целого листа» (FSR), метод «разделённого цилиндрического резонатора», которые все описаны как измерительные методики в стандарте IPC-TM-650. Первый метод основан на сравнении результатов измерений «пустого» резонатора, то есть заполненного воздухом, и резонатора с помещённым внутрь образцом материала. Точность этого метода зависит от точности измерения толщины образца и объёмов резонатора. Метод позволяет определить эпсилон в плоскости x-y, но не по оси z. Второй метод предполагает использование целого листа материала с медью, измерения проводятся со свипированием по частоте, при этом определяются стоячие волны (резонансные пики). Лист ламината с медью ведёт себя как волновод с открытыми стенками; при измерениях фиксируются стоячие волны, возникающие в продольной оси листа. Зная размеры листа и измерив резонансные частоты, можно вычислить диэлектрическую проницаемость материала на резонансной частоте. Этот метод хорошо подходит для длинных волн и низких частот, но не точен при определении более тонких цепей (пп: имеется в виду, что погрешность измерения толщины толстого листа материала не так значительна по сравнению с измерением тонкого листа, а как известно, в целях уменьшения потерь на излучения на высоких частотах обычно используют тонкую подложку). Этот перевод выполнен Leka_engineer.

примечание переводчика — иллюстрации

Метод «разделённого объёмного резонатора» проиллюстрирую картинкой из апноута Keysight:

6 метод SPDR

6 метод SPDR

Фото оснастки из апноута:

7 вид оснастки при измерениях методом "разделённого объёмного резонатора" (SPDR)

7 вид оснастки при измерениях методом «разделённого объёмного резонатора» (SPDR)

Ввод сигнала также может быть реализован по вертикальной оси (картинка из публикации «Microwave and RF methods of contactless mapping of the sheet resistance and the complex permittivity of conductive materials and semiconductors» Jerzy Krupka, Danh Nguyen and Janina Mazierska):

8 другая реализация метода "разделённого объёмного резонатора"

8 другая реализация метода «разделённого объёмного резонатора»

Интересно, таким образом тоже эпсилон в плоскости x-y измеряется?

В дополнение к рис.3 вот ещё одна иллюстрация метода «целого листа» (источник — презентация Rogers):

9 иллюстрация FSR

9 иллюстрация FSR

Третий метод (разделённого цилиндрического резонатора) состоит в том, что образец материала помещается в центре объёма резонатора цилиндрической формы. Одна половина зафиксирована, а вторая позволяет раздвинуть половинки резонатора, чтоб можно быть помещать образцы разной толщины. В стенке каждой половине цилиндра есть отверстие, куда вставлен кабель с петлёй связи на конце. Таким образом измеряется поле, касательное к плоскости х-у образца, затем вычисляется Dk материала.

примечание переводчика — иллюстрации

На рисунке ниже показана схема установки при измерении параметров материала методом «разделённого цилиндрического резонатора». Источник — апноут Keysight

10 метод разделённого цилиндрического резонатора (схема)

10 метод разделённого цилиндрического резонатора (схема)

Фото установки в апноуте также приведено. А вот другое фото (источник):

Методы, основанные на топологии также различны по своим применениям и получаемым результатам. Такие методики могут быть основаны на измерении коэффициентов передачи и отражения разных линий передач или структур или на измерении частоты и фазы печатного резонатора. Типы линий передач, используемых в методах оценки эпсилон: микрополосковая, симметричная, копланарная. Типы используемых резонаторных структур: резонатор в виде кольца и полосовые фильтры, построенные на резонаторах.

Высокая точность оценки параметров материала обеспечивается точностью измерений размеров материала и элементов топологии, ширины микрополосковой линии, толщины медного проводника, толщины подложки. Очевидно, точные измерения этих параметров становятся сложно выполнимыми для цепей, рассчитанных на частоту в мм-диапазоне. Вариации толщины материала и шероховатость меди также больше сказываются в мм-диапазоне частот, что приводит к менее точному определению Dk материала. Более гладкие медные проводники формируют более короткие пути тока и значения эпсилон неоднозначно. Такие физические отклонения в цепи также влияют на резонансную частоту печатных резонаторов, где очень важно точное измерение частоты и фазы.

Было изобретено множество методов и способов оценки диэлектрической проницаемости материала. В то время как результаты измерения Dk одного материала одним и тем же методом при повторных тестах могут совпадать, результаты измерений этого же материала различными методами будут отличаться. Проще говоря, разные тестовые топологии и оснастки работают по-разному. Различия в результатах измерений могут быть быть минимизированы только при применении одного и того же метода каждый раз. Но выбранный ранее метод может не обеспечивать получение значения Dk на нужной частоте, особенно часто такое происходит, когда разработчика интересует эпсилон материала в мм-диапазоне. Понимая, как отличаются методы оценки Dk, может и невозможно определить идеальный метод на все случаи жизни, но можно хотя бы выбрать наилучший исходя из дальнейшего применения.

Спасибо за внимание! Следующая статья будет авторская, на тему производства СВЧ-плат в России (апдейт прошлогодней статьи). В моём ВК недавно вышла статья про измерения полосовых фильтров на Wangling.


ссылка на оригинал статьи https://habr.com/ru/articles/752856/

SpaceX провела статические огневые испытания Super Heavy и водяной системы защиты стартовой установки

SpaceX успешно провела статические огневые испытания первой ступени ракеты-носителя Super Heavy. Также компания испытала водяную систему защиты стартовой установки, которая позволит предотвратить её повреждение.

Ракета выдержала испытание, а стартовая установка не получила видимых повреждений. Однако тест завершился через 2,74 секунды, что почти вдвое меньше запланированных пяти секунд. Кроме того, четыре из 33 основных двигателей Raptor отключились раньше времени. Испытанная ракета была оснащена двигателями Raptor 2, а сейчас SpaceX работает над модернизированной версией Raptor 3.

Тестирование прошло в рамках подготовки нового полётного испытания корабля Starship. Глава SpaceX Илон Маск заявил, что «вероятность достижения орбитальной скорости составляет около 50%, однако даже успешное разделение ступеней было бы победой».

Ранее SpaceX провела испытание под полным давлением водяной системы защиты установки. Она состоит из очень толстой перфорированной стальной пластины, расположенной непосредственно под ракетой, и активирует нескольких огромных водяных струй, которые постоянно охлаждают её водой, даже когда запускается ракетный двигатель.

20 апреля SpaceX предприняла попытку тестового запуска Starship. Через несколько минут полёта ракету закрутило, а процесс разделения не произошёл. В итоге тестовый запуск завершился аварией. Маск признал конструктивный просчёт со стартовым столом.


ссылка на оригинал статьи https://habr.com/ru/articles/752898/

Полиция Детройта арестовала за угон беременную женщину из-за ложного срабатывания системы распознавания лиц

Порша Вудрафф будет судиться с властями Детройта из-за ареста за угон автомобиля, который она не совершала. Программа распознавания лиц ложно идентифицировала женщину на восьмом месяце беременности как преступницу, сопоставив её изображение с видеозаписью угона. 

nytimes.com

nytimes.com

Вудрафф арестовали утром 16 февраля 2023 года, когда она собирала детей в школу. 

32-летняя женщина пыталась объяснить, что она не имеет отношения к угону, а также указала на свою беременность. Несмотря на это, на неё надели наручники и доставили в Детройтский центр заключения. Там Вудрафф удерживали в течение 11 часов, пока шёл допрос. Кроме того, у неё изъяли iPhone для поиска улик.

«У меня были схватки в камере предварительного заключения. Я испытывала острые боли в области спины. У меня были спазмы. Вероятно, это была паническая атака», — так Вудрафф описала свой арест.

В итоге после предъявления обвинения в грабеже и угоне автомобиля в тот же вечер женщину освободили под залог в размере $100 000. Она обратилась в больницу, где ей поставили диагноз «обезвоживание» и поставили две капельницы. 

Месяц спустя прокурор округа Уэйн закрыл дело против Вудрафф.

Согласно отчёту следователя из Департамента полиции Детройта, женщину идентифицировала система распознавания лиц. Вудрафф стала шестым человеком, сообщившим о ложном обвинении в совершении преступления из-за ложного срабатывания технологии. При этом все шесть человек были чернокожими, но она была первой женщиной среди них.

Эксперты по технологиям Национальной ассоциации адвокатов по уголовным делам отметили, что правоохранители осведомлены о рисках применения таких систем, но, тем не менее, инциденты с ложными обвинениями продолжаются.

Департамент полиции использует продукт поставщика средств распознавания лиц под названием DataWorks Plus для сопоставления неизвестных лиц с базой данных фотографий преступников. Система возвращает совпадения, ранжированные по вероятности. Результат её работы оценивает аналитик-человек. В полицейском отчете говорится, что криминалист выбрал Вудрафф, так как ранее женщину уже арестовывали в 2015 году. Она подтвердила, что была задержана за вождение с просроченными правами.

Слева: фотография, сделанная в 2015 году, которая использовалась для распознавания лица Вудрафф. Справа: ее фото, сделанное в 2021 году / nytimes.com

Слева: фотография, сделанная в 2015 году, которая использовалась для распознавания лица Вудрафф. Справа: ее фото, сделанное в 2021 году / nytimes.com

Также в отчёте полиции говорится, что через пять дней после угона автомобиля детектив попросил жертву посмотреть фотографии шести чернокожих женщин, которых подозревали в преступлении. Он опознал именно Вудрафф, и это послужило основанием для её ареста. 

Профессор психологии Гэри Уэллс считает, что сочетание технологии распознавания лиц с опознанием свидетеля не должно быть основанием для обвинения. По его мнению, свидетель, которого просят провести такое же сравнение, скорее всего, повторит ошибку, допущенную компьютером.

Вудрафф же говорит, что её арестовали на глазах у соседей, а её дочери пережили травму. По словам женщины, её спасло только то, что женщина, которая действительно участвовала в угоне автомобиля, не была беременна.

При этом Детройт уже столкнулся с тремя судебными исками за неправомерные аресты. Например, Роберта Уильямса ошибочно арестовали в январе 2020 года по подозрению в магазинной краже. Cистема пометила его на основании фотографии из водительского удостоверения. В иске мужчина требует обязать полицию собирать больше доказательств для задержаний.


ссылка на оригинал статьи https://habr.com/ru/articles/752894/